#include "command.h"
#include "global.h"
#include "utils.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include "history.h"
#include "parser.h"
#include "external.h"
 
command         CSSH_cmd_table[MAX_INTERNAL_COMMANDS];

/*********************************************************************
 * Registring command by name in internall command list
 * name: name for command
 * fnc: Function poinetr to speciefed command
 * 
 * Return:
 * FINE when registring succesfull
 * ERROR whan the list is full
 ********************************************************************/

int 
register_command(const char *name, fcall fnc, char * help, cmdHistory hist)
{
  int             count = 0;
  for (count = 0; count <= MAX_INTERNAL_COMMANDS; count++) {
    if (CSSH_cmd_table[count].fnc == 0) {
      #ifdef DEBUG
      printf("Command[%s] registred on slot [%i] \n", name, count);
      #endif
      strcpy(CSSH_cmd_table[count].cmd, name);
      if(help !=0) 
	{
	  CSSH_cmd_table[count].help = malloc(strlen(help)+1);
	  strcpy(CSSH_cmd_table[count].help ,help);
	}; 
      CSSH_cmd_table[count].fnc = fnc;
      CSSH_cmd_table[count].store = hist;
      return FINE;	/* Succesfull */
    };
  };
  return ERROR;		/* unsuccesfull */
}


/*********************************************************************
 * run internall command by      
 *
 * the name of command is holded @ firest index of param list
 * the total number of parameters ar in args valable
 *
 * return: the return status of found command OR
 * EXTERN return status whan command not found 
 *
 **********************************************************************/ 
int 
run_command(char * cmdline)
{
  command        *internall_cmd = 0;
  char* args[512];
  int argc;
  int ret ;

  argc = parser(cmdline, args);
  internall_cmd = get_command(args[0]);
  if ( internall_cmd != 0 )
    {
      /*We found command now we can check is storeable*/
      if (internall_cmd->store == STORE)
     	add_history_entry(cmdline);

      /*If passed any argument to function*/
      if ( argc >= 1 ) 
	/*if this argument is -h*/
	if( strcmp(args[1], "-h")== 0 ) 
	  {
	    /*if help is present*/
	    if( internall_cmd->help != 0) 
	      {
		/*print help*/
		printf("Uasge: %s\n",internall_cmd->help); 
      free_args(argc,args);
		return FINE;
	      }
	  }; /*Not help print*/
      
      ret = internall_cmd->fnc(argc, args);
      free_args(argc,args);
      return ret;
    } 
 
  /*otherwise*/
  add_history_entry(cmdline);
  run_external( argc , args);
  free_args(argc,args);  
  return FINE;
}



/*********************************************************************
 * get command by name 
 *
 *********************************************************************/
command * get_command( char * name)
{
  command        *internall_cmd = 0; 
  for (internall_cmd = CSSH_cmd_table; internall_cmd->fnc != 0; internall_cmd++) {
    if (strcmp(internall_cmd->cmd, name) == 0) 
      return internall_cmd;
  }  
  return 0; 
}

/*******************************************
 * getPath command                 
 *                         
 *
 *******************************************/
int cmd_get_path(int argc, char * param[])
{

  printf("PATH:=%s\n",getenv("PATH"));
  return FINE;

}

/******************************************
 * setPath command
 ******************************************/

int 
cmd_set_path(int argc , char * args[])
{
  
  if ( argc != 1 ) 
    {
      printf ( "Usage : setpath <path> \napplay the path to system/user path \n");
      return FINE;
    };

  if(setenv("PATH", args[1],1))
    {
      myperror("setenv");
      return ERROR;
    }
  return FINE;
}



/*******************************************
 * Command to exit shell:                 
 * -h show help                           
 *
 *******************************************/
int 
cmd_exit(int args, char *param[])
{
  save_to_file(".hist_list");
  setenv("PATH", CSSH_globals.pro_path,1);
  exit(0);
  return FINE;
}

/********************************************
 * Show help about internall command
 * -h show help                             
 ********************************************/
int cmd_help(int args, char * param[])
{
  command * com = 0;
  if ( args == 0 ) 
    {
      printf ("Usage: help <command> to show help\n");
      return FINE;
    };
  com = get_command(param[1]);
  if ( com != 0) 
    printf("%s\n",com->help);
  else 
    printf("Command %s is not internall command try %s -h for its own help\n", param[1],param[1]);  
  return FINE;
}


/***********************************************************
 * Print working directory
 * 
 ***********************************************************/
int cmd_pwd(int argc , char * args[])
{
  char cwd[512];
  getcwd(cwd,512);
  printf ("%s\n",cwd);
  return FINE;
}




/***********************************************************
 * list curent history
 ***********************************************************/
int cmd_print_hist(int argc , char * args[])
{
  list_history_entries();
  return FINE;
}

/***********************************************************
 * run last command from history
 ***********************************************************/
int cmd_runl_hist(int argc , char * args[])
{
  run_command((char *)get_last_cmd());
  return FINE;
}

/***********************************************************
 * run last command from history
 ***********************************************************/
int cmd_runnb_hist(int argc , char * args[])
{
  int to_run;
  char * cmdline;
  if(argc == 0) 
    {
    USAGE:
      printf ("Usage ! <nb> : to run command nb from history\nTO view history use command history\n");
      return FINE;
    };
  to_run = atoi(args[1]);
  /*if user put not number as parameter*/
  if ( to_run == 0) 
    goto USAGE;

  cmdline = get_cmd_nb(to_run);
  /*if user put number grater then number of entries in istory*/
  if( cmdline[0] == '\0' )
    goto USAGE;
 
  run_command(cmdline);
  return FINE;
}


/***********************************************************
 * Change working directory
 * No parameters go to home dir
 * parameter go to param dir
 * Return:
 * fine change direcory finished succesfuky
 * ERROR some error 
 ***********************************************************/
int cmd_cd(int argc , char * args[])
{
  if (argc == 0 )
    {
      if (chdir(CSSH_globals.hom_path)!=0)
	{
	NOFILE:
	  printf("No file or directory!\n");
	  return FINE;
	};
      return FINE;
    }
  if( chdir( args[1])!=0) goto NOFILE;
  return FINE;
}



/***********************************************************
 * dummy command call
 * 
 ***********************************************************/
int cmd_notImplaemented(int argc , char * args[])
{
  int i ;
  for (i =0 ; i <= argc; ++i)
    {
      printf ("%i '%s' \n",i, args[i]);
    }
  
  printf("Command %s not implemented yet .. :( \n" , args[0]);
  return FINE;
}

/***********************************************************
 * utility function to registry all implemented commands
 * 
 ***********************************************************/
void 
init_commands()
{
  register_command("exit", cmd_exit,"Type exit to exit the shell",STORE);
  register_command("help", cmd_help,"Usage: help <command> to get help",STORE);
  register_command("pwd" , cmd_pwd, "Print working direstory",STORE);
  register_command("history"   ,cmd_print_hist, "list command history",STORE);
  register_command("!"   ,cmd_runnb_hist, "Usage: ! <command nb> run command by number from history",NOSTORE);
  register_command("!!"   ,cmd_runl_hist, "Run last command form history ",NOSTORE);
  register_command("getpath",cmd_get_path, "Print curent path valable ",STORE);
  register_command("setpath",cmd_set_path, "Set new path value",STORE);  
  register_command("cd",cmd_cd, "Change working directory\nWith no parameter change it ti home ",STORE);  
}


/***********************************************************
 * free used memmory for parameters
 **********************************************************/
void  free_args(int argc, char * args[])
{
  int i;
  for(i =0 ; i<= argc ; i++)
    if(args[i]!=0)
      {
	free(args[i]);
	args[i]=0;
      };
}
